﻿using System;
using System.Diagnostics;
using System.Globalization;
using System.Linq;
using InterfacesPhoneCommands;
using VirtualMachines;
using MultiTargeting = Microsoft.SmartDevice.MultiTargeting.Connectivity;

namespace PhoneControl
{
    public class PhoneControl : IPhoneService, IService
    {
        private static PhoneControl _currentControl;
        private static readonly object SyncRoot = new object();

        private Exception _criticalError;
        private bool _isInit;

        private IPhoneApi _phoneInstance;
        private bool _started;
        private readonly ConnectableDevice[] _devices;
        private ConnectableDevice _selectedDevice;

        private PhoneControl()
        {
            try
            {
                var multiConnect = new MultiTargeting.MultiTargetingConnectivity(CultureInfo.InvariantCulture.LCID);
                var devs = multiConnect.GetConnectableDevices();
                _devices = devs.Select(connectableDevice => new ConnectableDevice
                {
                    Id = connectableDevice.Id,
                    Name = connectableDevice.Name,
                    IdNative = connectableDevice.IdNative(),
                    IsEmulator = connectableDevice.IsEmulator(),
                    IsLegacyEmulator = connectableDevice.IsLegacyEmulator()
                }).ToArray();
                HyperVControl.Instance.ChangedMachineStatus+=InstanceOnChangedMachineStatus;
            }
            catch (Exception ex)
            {
                _criticalError = ex;
            }
        }

        private void InstanceOnChangedMachineStatus(object sender, ChangedMachineStatusEventArgs changedMachineStatusEventArgs)
        {
            if (ChangedMachineStatus != null)
            {
                ChangedMachineStatus(this, changedMachineStatusEventArgs);
            }
        }

        public ResponseConnectableDevice ConnectableDevice()
        {
            return new ResponseConnectableDevice{Successful = true,Value = _devices};
        }

        #region instance

        public static PhoneControl Instance
        {
            get
            {
                if (_currentControl == null)
                {
                    lock (SyncRoot)
                    {
                        if (_currentControl == null)
                        {
                            // ReSharper disable PossibleMultipleWriteAccessInDoubleCheckLocking
                            _currentControl = new PhoneControl();
                            // ReSharper restore PossibleMultipleWriteAccessInDoubleCheckLocking
                        }
                    }
                }
                return _currentControl;
            }
        }

        #endregion

        public ResponseConnectableDevice Device()
        {
            if (_phoneInstance == null)
            {
                return new ResponseConnectableDevice { ErrorMessage = "PhoneControl: Instance not created", Successful = false };
            }
            var result = _phoneInstance.Device();
            return result;
        }

        public ResponseConnectableDevice SelectConnectableDevice(string namedevice)
        {
            if (_devices == null)
            {
                return new ResponseConnectableDevice { ErrorMessage = "PhoneControl: Instance not created", Successful = false };
            }
            _selectedDevice = _devices.FirstOrDefault(d => d.Name.ToLower() == namedevice.ToLower());

            return _selectedDevice == null ? 
                new ResponseConnectableDevice { ErrorMessage = "Device not found", Successful = false }
                : new ResponseConnectableDevice { Successful = true, Value = new[] { _selectedDevice } };
        }

        public ResponseVoid Connect()
        {
            if (_selectedDevice == null)
            {
                return new ResponseVoid { ErrorMessage = "PhoneControl: Devive not selected", Successful = false };
            }

            if (_phoneInstance != null)
            {
                if (_phoneInstance.IsConnected().Successful)
                {
                    var name = _phoneInstance.Device().Value[0].Name;
                    var dresult = _phoneInstance.Disconnect();
                    if (!dresult.Successful)
                    {
                        return new ResponseVoid { ErrorMessage = "PhoneControl: Disconnected " + name + "error: " + dresult.ErrorMessage, Successful = false };
                    }
                }
            }

            if (_selectedDevice.IsLegacyEmulator)
            {
                _phoneInstance = new Phone7.PhoneApi();
            }
            else
            {
                _phoneInstance = new Phone8.PhoneApi();
            }
            return  _phoneInstance.ConnectPhone(_selectedDevice.IdNative);
        }

        public ResponseVoid CloseEmulator(string title)
        {
            try
            {
                var xdeprocess = Process.GetProcessesByName("XDE");
                foreach (var process in xdeprocess.Where(process => process.MainWindowTitle == title))
                {
                    process.CloseMainWindow();
                }
            }
            catch (Exception ex)
            {
                return new ResponseVoid { ErrorMessage = ex.Message };
            }
            return new ResponseVoid {Successful = true};
        }

        public ResponseVirtualMachines Machines(bool reload)
        {
            return HyperVControl.Instance.Machines(reload);
        }

        public ResponseVoid CleanUpMachines()
        {
            return HyperVControl.Instance.CleanUpMachines();
        }

        public ResponseVoid CloseMachine(string nameVm)
        {
            return HyperVControl.Instance.CloseMachine(nameVm);
        }

        public ResponseVoid CreateSnapshot(string vmName, string nameSnapshot)
        {
            var cmd = HyperVControl.Instance.CreateSnapshot(vmName,nameSnapshot);
            if (cmd.Successful)
            {
                var vm = HyperVControl.Instance.FindVirtualMachine(vmName);
                if (vm != null)
                {
                    InstanceOnChangedMachineStatus(this, new ChangedMachineStatusEventArgs(vm));
                }
            }
            return cmd;
        }

        public ResponseVoid DeleteSnapshot(string vmName, string nameSnapshot)
        {
            return HyperVControl.Instance.DeleteSnapshot(vmName, nameSnapshot);
        }

        public void CloseXdeVirtualMachines()
        {
            HyperVControl.Instance.CloseXdeVirtualMachines();
        }

        public VirtualMachine FindVirtualMachine(string vmName)
        {
            return HyperVControl.Instance.FindVirtualMachine(vmName);
        }

        public event EventHandler<ChangedMachineStatusEventArgs> ChangedMachineStatus;

        public ResponseVoid ConnectPhone(string guidDevice)
        {
            if (_phoneInstance == null)
            {
                return new ResponseVoid { ErrorMessage = "PhoneControl: Instance not created", Successful = false };
            }
            if (_phoneInstance.IsConnected().Successful)
            {
                var name = _phoneInstance.Device().Value[0].Name;
                var dresult =  _phoneInstance.Disconnect();
                if (!dresult.Successful)
                {
                    return new ResponseVoid { ErrorMessage = "PhoneControl: Disconnected " + name + "error: " + dresult.ErrorMessage, Successful = false };
                }
            }
            _selectedDevice = _devices.FirstOrDefault(d => d.Id.ToLower() == guidDevice.ToLower());
            if (_selectedDevice == null)
            {
                return new ResponseVoid { ErrorMessage = "PhoneControl: Device not found", Successful = false };
            }
            return _phoneInstance.ConnectPhone(guidDevice);
        }

        public ResponseVoid IsConnected()
        {
            if (_phoneInstance == null)
            {
                return new ResponseVoid { ErrorMessage = "PhoneControl: Instance not created", Successful = false };
            }
            return _phoneInstance.IsConnected();
        }

        public ResponseSystemInfo SystemInfo()
        {
            if (_phoneInstance == null)
            {
                return new ResponseSystemInfo { ErrorMessage = "PhoneControl: Instance not created", Successful = false };
            }
            return _phoneInstance.SystemInfo();
        }

        public ResponseVoid Disconnect()
        {
            if (_phoneInstance == null)
            {
                return new ResponseVoid { ErrorMessage = "PhoneControl: Instance not created", Successful = false };
            }
            return _phoneInstance.Disconnect();
        }

        public ResponseVoid Launch(string guidapp)
        {
            if (_phoneInstance == null)
            {
                return new ResponseVoid { ErrorMessage = "PhoneControl: Instance not created", Successful = false };
            }
            return  _phoneInstance.Launch(guidapp);
        }

        public ResponseVoid TerminateRunningInstances(string guidapp)
        {
            if (_phoneInstance == null)
            {
                return new ResponseVoid { ErrorMessage = "PhoneControl: Instance not created", Successful = false };
            }
            return _phoneInstance.TerminateRunningInstances(guidapp);
        }

        public ResponseVoid Uninstall(string guidapp)
        {
            if (_phoneInstance == null)
            {
                return new ResponseVoid { ErrorMessage = "PhoneControl: Instance not created", Successful = false };
            }
            return _phoneInstance.Uninstall(guidapp);
        }

        public ResponseVoid InstallApplication(Guid guid, Guid instance, string genre, string iconpath,
                                               string xapPackege)
        {
            if (_phoneInstance == null)
            {
                return new ResponseVoid { ErrorMessage = "PhoneControl: Instance not created", Successful = false };
            }
            return _phoneInstance.InstallApplication(guid, instance, genre, iconpath, xapPackege);
        }

        public ResponseVoid IsApplicationInstalled(Guid guidapp)
        {
            if (_phoneInstance == null)
            {
                return new ResponseVoid { ErrorMessage = "PhoneControl: Instance not created", Successful = false };
            }
            return _phoneInstance.IsApplicationInstalled(guidapp);
        }

        public ResponseVoid UpdateApplication(string guidapp, string genre, string iconfile, string filename)
        {
            if (_phoneInstance == null)
            {
                return new ResponseVoid { ErrorMessage = "PhoneControl: Instance not created", Successful = false };
            }
            return _phoneInstance.UpdateApplication(guidapp, genre, iconfile, filename);
        }

        public ResponseArrayString ApplicationsInstalled()
        {
            if (_phoneInstance == null)
            {
                return new ResponseArrayString { ErrorMessage = "PhoneControl: Instance not created", Successful = false };
            }
            return _phoneInstance.ApplicationsInstalled();
        }

        public ResponseRemoteFile GetIsoFiles(string guidapp, string pathRoot)
        {
            if (_phoneInstance == null)
            {
                return new ResponseRemoteFile { ErrorMessage = "PhoneControl: Instance not created", Successful = false };
            }
            return _phoneInstance.GetIsoFiles(guidapp, pathRoot);
        }

        public ResponseVoid CopySendFile(string guidapp, RemoteFile isofileinfo, string newfile, bool overwrite)
        {
            if (_phoneInstance == null)
            {
                return new ResponseVoid { ErrorMessage = "PhoneControl: Instance not created", Successful = false };
            }
            return _phoneInstance.CopySendFile(guidapp, isofileinfo, newfile, overwrite);
        }

        public ResponseVoid CopyReceiveFile(string guidapp, RemoteFile isofileinfo, string desktopTarget)
        {
            if (_phoneInstance == null)
            {
                return new ResponseVoid { ErrorMessage = "PhoneControl: Instance not created", Successful = false };
            }
            return _phoneInstance.CopyReceiveFile(guidapp, isofileinfo, desktopTarget);
        }

        public ResponseVoid RenameFile(string guidapp, RemoteFile isofileinfo, string newfile)
        {
            if (_phoneInstance == null)
            {
                return new ResponseVoid { ErrorMessage = "PhoneControl: Instance not created", Successful = false };
            }
            return _phoneInstance.RenameFile(guidapp, isofileinfo, newfile);
        }

        public ResponseVoid DeleteFile(string guidapp, RemoteFile isofileinfo)
        {
            if (_phoneInstance == null)
            {
                return new ResponseVoid { ErrorMessage = "PhoneControl: Instance not created", Successful = false };
            }
            return _phoneInstance.DeleteFile(guidapp, isofileinfo);
        }

        public ResponseVoid DeleteDir(string guidapp, RemoteFile isofileinfo)
        {
            if (_phoneInstance == null)
            {
                return new ResponseVoid { ErrorMessage = "PhoneControl: Instance not created", Successful = false };
            }
            return _phoneInstance.DeleteDir(guidapp, isofileinfo);
        }

        public ResponseVoid DirectoryExists(string guidapp, string folder)
        {
            if (_phoneInstance == null)
            {
                return new ResponseVoid { ErrorMessage = "PhoneControl: Instance not created", Successful = false };
            }
            return _phoneInstance.DirectoryExists(guidapp, folder);
        }

        public ResponseVoid FileExists(string guidapp, string file)
        {
            if (_phoneInstance == null)
            {
                return new ResponseVoid { ErrorMessage = "PhoneControl: Instance not created", Successful = false };
            }
            return _phoneInstance.FileExists(guidapp, file);
        }

        public ResponseVoid CreateDir(string guidapp, RemoteFile isofileinfo, string newfolder)
        {
            if (_phoneInstance == null)
            {
                return new ResponseVoid { ErrorMessage = "PhoneControl: Instance not created", Successful = false };
            }
            return _phoneInstance.CreateDir(guidapp, isofileinfo, newfolder);
        }

        public Exception CriticalError
        {
            get { return Instance._criticalError; }
        }

        public void InitService()
        {
            Instance._isInit = true;
            Instance._started = false;
            if (Instance._criticalError == null)
            {
                Start();
            }
        }

        public void Start()
        {
            if (!Instance._isInit || Instance._started || Instance._criticalError != null) return;
            Instance._started = false;
            Instance._criticalError = null;
            Instance._started = true;
        }

        public void Stop()
        {
            if (!Instance._started) return;
            Instance.Disconnect();
            Instance._started = false;
        }

        public string NameService()
        {
            return Instance.GetType().FullName;
        }

        public bool IsRunning()
        {
            if (Instance._criticalError != null || !Instance._started) return false;
            return true;
        }
    }
}